package com.sduept.nwld.dataserver.rest.fault;

import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortMeta;
import org.primefaces.model.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;

import com.sduept.bigdata.fault.entity.AnalLinefaultEtl;
import com.sduept.bigdata.fault.entity.FaultForecastModel;
import com.sduept.bigdata.fault.manager.FaultForecastIdentifyManager;
import com.sduept.bigdata.fault.manager.FaultReasonIdentifyManager;
import com.sduept.bigdata.fault.model.InputVector;
import com.sduept.bigdata.ml.bpclassifier.neuralnet.NeuralException;
import com.sduept.bigdata.ml.domain.LibSvmData;
import com.sduept.bigdata.weather.faultcause.manager.FaultCauseManager;
import com.sduept.bigdata.web.jsf.controller.AbstractController;
import com.sduept.generator.ObjectId;

/**
 * 故障原因辨识
 * 
 * @author Ningfw
 * @date 2017-08-19
 *
 */
@Named
@ViewScoped
public class FaultReasonIdentifyController extends AbstractController {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1092593262277709174L;

	@Autowired
	private FaultReasonIdentifyManager faultReasonIdentifyManager;
	@Autowired
	private FaultCauseManager faultCauseManager;
	@Autowired
	private FaultForecastIdentifyManager faultForecastIdentifyManager;

	private List<AnalLinefaultEtl> anals = new ArrayList<AnalLinefaultEtl>();
	private AnalLinefaultEtl selected = null;// 前台单选的数据
	private List<AnalLinefaultEtl> selectAnals = null;
	private LazyDataModel<AnalLinefaultEtl> analLinefaultEtl;
	private String faultEquipment;
	private Date startTime;
	private Date endTime;
	private List<String> resultMessList = new ArrayList<String>();// 返回结果
	private String resultMess;// 返回结果
	private boolean trainResFlag;// 模型训练结果，返回到前台，true时打开dialog，false时不打开
	private boolean resultFlag;// 返回到前台，true时打开dialog，false时不打开
	private List<String> modelTypeList = new ArrayList<String>();// 现有模型列表
	private String dataFileContent;// 输入文件的内容
	private List<InputVector> vecList = new ArrayList<InputVector>();// 输入文件的反编译后的内容
	private String modelFileContent;// 模型文件的内容
	private int flag;// 数据文件所要显示的内容标志
	private boolean lightingFlag = true;
	private boolean iceFlag = true;
	private boolean tempFlag = true;
	private boolean rhumdFlag = true;
	private boolean windFlag = true;
	private boolean windDirFlag = true;
	private int rowCount; // 懒加载-列表总计条数
	private FaultForecastModel createdModel = null;
	private int dataNum = 5;// 训练数据条数
	private int dataMaxNum;// 数据库现有数据条数
	private Double correctnessRate = 0.00;

	@PostConstruct
	public void init() {
		correctnessRate = 0.00;
		initTable();
		getLastInputVector();
//		getAllInputVector();
	}

	public void initTable() {
		// 模型预测数据生成
		anals.clear();
		findAll();
		dataMaxNum = faultReasonIdentifyManager.countAnalLinefaultEtl();
		// 现有model
		getModelType();
	}

	/**
	 * 分页查询全部数据模型
	 */
	public void findAll() {
		anals.clear();
		analLinefaultEtl = new LazyDataModel<AnalLinefaultEtl>() {

			private static final long serialVersionUID = -5083681736033783332L;

			@Override
			public List<AnalLinefaultEtl> load(int first, int pageSize, String sortField, SortOrder sortOrder,
					Map<String, Object> filters) {
				anals = faultReasonIdentifyManager.findAll(new int[] { first, first + pageSize });
				return anals;
			}

			@Override
			public List<AnalLinefaultEtl> load(int first, int pageSize, List<SortMeta> multiSortMeta,
					Map<String, Object> filters) {
				anals = faultReasonIdentifyManager.findAll(new int[] { first, first + pageSize });
				return anals;
			}

			@Override
			public AnalLinefaultEtl getRowData(String rowKey) {
				for (AnalLinefaultEtl t : anals) {
					if (t.getId().equals(rowKey)) {
						return t;
					}
				}
				return null;
			}

			@Override
			public Object getRowKey(AnalLinefaultEtl object) {
				for (AnalLinefaultEtl t : anals) {
					if (t.getId().equals(object.getId())) {
						return t;
					}
				}
				return null;
			}
		};
		rowCount = faultReasonIdentifyManager.countAnalLinefaultEtl();
		analLinefaultEtl.setRowCount(rowCount);
	}

	/**
	 * 检索
	 */
	public void search() {

		if ((null == faultEquipment || "".equals(faultEquipment)) && null == startTime && null == endTime) {
			addErrorMessage("请输入搜索信息！");
		} else {
			anals.clear();
			final String whereHql = faultReasonIdentifyManager.getConditionHql(faultEquipment, startTime, endTime);
			final Object[] whereArgs = faultReasonIdentifyManager.getConditionParam(faultEquipment, startTime, endTime);
			analLinefaultEtl = new LazyDataModel<AnalLinefaultEtl>() {

				private static final long serialVersionUID = -5083681736033783332L;

				@Override
				public List<AnalLinefaultEtl> load(int first, int pageSize, String sortField, SortOrder sortOrder,
						Map<String, Object> filters) {
					anals = faultReasonIdentifyManager.findByCondition(whereHql, whereArgs,
							new int[] { first, first + pageSize });
					return anals;
				}

				@Override
				public List<AnalLinefaultEtl> load(int first, int pageSize, List<SortMeta> multiSortMeta,
						Map<String, Object> filters) {
					anals = faultReasonIdentifyManager.findByCondition(whereHql, whereArgs,
							new int[] { first, first + pageSize });
					return anals;
				}

				@Override
				public AnalLinefaultEtl getRowData(String rowKey) {
					for (AnalLinefaultEtl t : anals) {
						if (t.getId().equals(rowKey)) {
							return t;
						}
					}
					return null;
				}

				@Override
				public Object getRowKey(AnalLinefaultEtl object) {
					for (AnalLinefaultEtl t : anals) {
						if (t.getId().equals(object.getId())) {
							return t;
						}
					}
					return null;
				}
			};
			rowCount = faultReasonIdentifyManager.countByCondition(whereHql, whereArgs);
			analLinefaultEtl.setRowCount(rowCount);
		}
	}

	/**
	 * 刷新
	 */
	public void refresh() {
		initTable();
		faultEquipment = null;
		startTime = null;
		endTime = null;
	}


	/**
	 * 训练BP神经网络 训练方法 现有的训练雷击、训练覆冰、训练火山、训练风偏、训练鸟害，都是调用这个方法
	 * 方法生成的训练文件，放到SystemProperties.FAULT_REASON_IDENTIFY_PATH路径下
	 * 
	 * @param reason 故障原因，"雷击" "覆冰" "火山" "风偏" "鸟害"
	 * @return
	 * @throws NeuralException
	 * @since 2019-04-13
	 */

	public String modelTrainingBP(String reason) throws NeuralException {
		List<LibSvmData> svmdatas = faultCauseManager.genLightTraningData(reason);
		if (svmdatas.size() < 5 || svmdatas.size() > dataMaxNum) {
			addErrorMessage("训练数据条数最小5条，最大" + dataMaxNum + "条！");
			trainResFlag = false;
		} else {
			correctnessRate = faultCauseManager.modelTraining(reason, svmdatas);
			resultMess = "训练模型正确率为： " + correctnessRate;
			trainResFlag = true;
		}
		return resultMess;
	}

	/**
	 * BP神经网络预测
	 * 
	 * @throws ParseException
	 * @throws SQLException
	 * @throws IOException
	 */
	public void modelForecastBP() throws IOException, SQLException, ParseException {
		if (null == selected) {
			addErrorMessage("请点击所要预测原因的数据！");
			resultFlag = false;
		} else {
			if (selected.getLongitude() == null || selected.getLatitude() == null) {
				addErrorMessage("所选数据的经纬度不能为空！");
				resultFlag = false;
			} else {

//				String equipmentId = selected.getEquipmentId();
//				String time = selected.getTime().toString();
//				Map<String, String> dataMap = new HashMap<>();
//				dataMap.put("equipmentId", equipmentId);
//				dataMap.put("time", time);
//				resultMessList = faultCauseManager.modelForecastBP(dataMap);
//				resultFlag = true;
			}

		}

	}

	/**
	 * 获取现有model，显示到前台
	 */
	public void getModelType() {
		List<FaultForecastModel> forecastModels = faultForecastIdentifyManager.findAll();
		for (FaultForecastModel model : forecastModels) {
			modelTypeList.add(model.getName());
		}
	}

	/**
	 * 读取现有的文件
	 * 
	 * @param modelType 模型
	 */
	public void readExistingFile(String modelType) {
	}

	/**
	 * 截取返回的文件内容
	 * 
	 * @param str
	 * @return
	 */
	public String substrContent(String str) {
		str = str.substring(str.indexOf(",") + 1);
		str = str.substring(str.indexOf(":") + 1).replace("\"", "").replace("}", "").trim();
		return str;
	}

	/**
	 * 获得所有数据样本，并更新inputVector 页面初次加载时调用
	 * 
	 * @since 2019-04-13
	 */
	public void getAllInputVector() {
		List<AnalLinefaultEtl> analList = faultCauseManager.findAll();
		vecList = faultCauseManager.generateInputVector(analList, null);
	}

	/**
	 * 获得最近的生成的数据模型（最近的100条）
	 */
	public void getLastInputVector() {
		List<AnalLinefaultEtl> analList = faultCauseManager.findLastAnalLinefaultEtl();
		vecList = faultCauseManager.generateInputVector(analList, null);
	}

	/**
	 * 根据类型获得数据样本，并更新inputVector
	 * 
	 * @param modelType 模型类型 "雷击" "风偏" "火山" "覆冰" "鸟害"
	 * @since 2019-04-13
	 */
	public void getInputVectorByModelType(String modelType) {
		List<AnalLinefaultEtl> analList = new ArrayList<>();
		analList = faultCauseManager.findByModelType(modelType);
		vecList = faultCauseManager.generateInputVector(analList, modelType);
		dataNum = analList.size();
	}

	/**
	 * 多条原因预测
	 * 
	 * @since 2019-04-16
	 */
	public void multipleModelPredict() {
		if (selectAnals == null || selectAnals.size() == 0) {
			addErrorMessage("请点击所要预测原因的数据！");
			resultFlag = false;
		} else {
			resultMessList = faultCauseManager.modelPredict(selectAnals);
			resultFlag = true;
		}
	}

	/**
	 * 
	 */
	public void createModel() {
		createdModel = new FaultForecastModel();
	}

	public void editModel(String modelType) {
		createdModel = faultForecastIdentifyManager.findByName(modelType);
	}

	public void saveModel() {
		if (createdModel.getId() == null) {
			createdModel.setId(ObjectId.get().toString());
			faultForecastIdentifyManager.createOrUpdate(createdModel);
			modelTypeList.add(createdModel.getName());
		} else {
			faultForecastIdentifyManager.createOrUpdate(createdModel);
		}
		addSuccessMessage("保存成功！");
		createdModel = null;
	}

	public void deleteModel(String modelType) {
		if (modelType != null) {
			FaultForecastModel deleteModel = faultForecastIdentifyManager.findByName(modelType);
			faultForecastIdentifyManager.delete(deleteModel.getId());
			modelTypeList.remove(modelType);
			addSuccessMessage("删除成功！");
		}
	}

	public AnalLinefaultEtl getSelected() {
		return selected;
	}

	public void setSelected(AnalLinefaultEtl selected) {
		this.selected = selected;
	}

	public LazyDataModel<AnalLinefaultEtl> getAnalLinefaultEtl() {
		return analLinefaultEtl;
	}

	public void setAnalLinefaultEtl(LazyDataModel<AnalLinefaultEtl> analLinefaultEtl) {
		this.analLinefaultEtl = analLinefaultEtl;
	}

	public int getDataNum() {
		return dataNum;
	}

	public void setDataNum(int dataNum) {
		this.dataNum = dataNum;
	}

	public int getDataMaxNum() {
		return dataMaxNum;
	}

	public void setDataMaxNum(int dataMaxNum) {
		this.dataMaxNum = dataMaxNum;
	}

	public List<String> getResultMessList() {
		return resultMessList;
	}

	public void setResultMessList(List<String> resultMessList) {
		this.resultMessList = resultMessList;
	}

	public String getResultMess() {
		return resultMess;
	}

	public void setResultMess(String resultMess) {
		this.resultMess = resultMess;
	}

	public boolean isTrainResFlag() {
		return trainResFlag;
	}

	public void setTrainResFlag(boolean trainResFlag) {
		this.trainResFlag = trainResFlag;
	}

	public boolean isResultFlag() {
		return resultFlag;
	}

	public void setResultFlag(boolean resultFlag) {
		this.resultFlag = resultFlag;
	}

	public List<String> getModelTypeList() {
		return modelTypeList;
	}

	public void setModelTypeList(List<String> modelTypeList) {
		this.modelTypeList = modelTypeList;
	}

	public String getDataFileContent() {
		return dataFileContent;
	}

	public void setDataFileContent(String dataFileContent) {
		this.dataFileContent = dataFileContent;
	}

	public String getModelFileContent() {
		return modelFileContent;
	}

	public void setModelFileContent(String modelFileContent) {
		this.modelFileContent = modelFileContent;
	}

	public int getFlag() {
		return flag;
	}

	public void setFlag(int flag) {
		this.flag = flag;
	}

	public List<InputVector> getVecList() {
		return vecList;
	}

	public void setVecList(List<InputVector> vecList) {
		this.vecList = vecList;
	}

	public String getFaultEquipment() {
		return faultEquipment;
	}

	public void setFaultEquipment(String faultEquipment) {
		this.faultEquipment = faultEquipment;
	}

	public Date getStartTime() {
		return startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public Date getEndTime() {
		return endTime;
	}

	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}

	public boolean isLightingFlag() {
		return lightingFlag;
	}

	public void setLightingFlag(boolean lightingFlag) {
		this.lightingFlag = lightingFlag;
	}

	public boolean isIceFlag() {
		return iceFlag;
	}

	public void setIceFlag(boolean iceFlag) {
		this.iceFlag = iceFlag;
	}

	public boolean isTempFlag() {
		return tempFlag;
	}

	public void setTempFlag(boolean tempFlag) {
		this.tempFlag = tempFlag;
	}

	public boolean isRhumdFlag() {
		return rhumdFlag;
	}

	public void setRhumdFlag(boolean rhumdFlag) {
		this.rhumdFlag = rhumdFlag;
	}

	public boolean isWindFlag() {
		return windFlag;
	}

	public void setWindFlag(boolean windFlag) {
		this.windFlag = windFlag;
	}

	public boolean isWindDirFlag() {
		return windDirFlag;
	}

	public void setWindDirFlag(boolean windDirFlag) {
		this.windDirFlag = windDirFlag;
	}

	public int getRowCount() {
		return rowCount;
	}

	public void setRowCount(int rowCount) {
		this.rowCount = rowCount;
	}

	public List<AnalLinefaultEtl> getSelectAnals() {
		return selectAnals;
	}

	public void setSelectAnals(List<AnalLinefaultEtl> selectAnals) {
		this.selectAnals = selectAnals;
	}

	public FaultForecastModel getCreatedModel() {
		return createdModel;
	}

	public void setCreatedModel(FaultForecastModel createdModel) {
		this.createdModel = createdModel;
	}

	public Double getCorrectnessRate() {
		return correctnessRate;
	}

	public void setCorrectnessRate(Double correctnessRate) {
		this.correctnessRate = correctnessRate;
	}

}
